perm filename FACADE.SAI[REV,MUS] blob
sn#445187 filedate 1979-05-24 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00045 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00005 00002 BEGIN "FACADE"
C00006 00003 DEFINE DEFAULT_SAVE_FILE=⊂"SAVED.REV"⊃
C00008 00004 DEFINE HELP_TEXT=⊂"
C00009 00005 ∂ Declarations for unit reverberator manipulation routines.
C00011 00006 ∂ Declarations for tree manipulation routines.
C00014 00007 ∂ Declarations for impulse response display routine.
C00016 00008 ∂ Declarations for JAM's display routines.
C00018 00009 ∂ Declarations for piece of glass manipulation routines.
C00019 00010 ∂ Declarations for scanning routines.
C00022 00011 EXTERNAL PROCEDURE instrument_print(
C00025 00012 INTEGER PROCEDURE file_channel(
C00028 00013 PROCEDURE save_the_tree(
C00035 00014 PROCEDURE save_the_world(
C00038 00015 PROCEDURE HELP_clear
C00039 00016 PROCEDURE DCLEAR(
C00040 00017 PROCEDURE esc_break(
C00043 00018 PROCEDURE label_print(
C00046 00019 PROCEDURE unit_print(
C00049 00020 PROCEDURE units_print(
C00051 00021 PROCEDURE tree_print(
C00054 00022 PROCEDURE update_display(
C00057 00023 ∂ ... update_display ... continued.
C00059 00024 ∂ Declarations for THE_WORLD.
C00061 00025 PROCEDURE initialize_the_world
C00063 00026 ∂ Top level.
C00065 00027 WHILE
C00067 00028 CASE
C00069 00029 ["A"] ∂ APPEND
C00072 00030 ["D"] ∂ DELAY_TIME
C00076 00031 ["F"] ∂ FREQUENCY
C00079 00032 ["H"] ∂ HELP
C00081 00033 ["I"] ∂ IMPULSE
C00085 00034 ["K"] ∂ KILL
C00087 00035 ["L"] ∂ LAST_IMPULSE
C00090 00036 ["O"] ∂ OUTPUT
C00093 00037 ["S"] ∂ SAVE_THE_WORLD
C00096 00038 ["W"] ∂ WALL_DISTANCE
C00099 00039 [""""] ∂ COPY_NODE_INTO_UNIT
C00101 00040 ["@"] ∂ READ_COMMANDS_FROM_FILE
C00104 00041 ["?"] ∂ HELP prefix
C00106 00042 ["←"] ∂ MOVE_TO_INPUT
C00109 00043 [0] ∂ NULL COMMAND
C00110 00044 END "command loop"
C00111 00045 END "FACADE"
C00112 ENDMK
C⊗;
BEGIN "FACADE"
REQUIRE "HEADER.SAI" SOURCE_FILE;
∂ Ken Shoemake. December 1976.
This module is the main control program for REVED. It handles the displays
and decides what to do with the commands. Naturally it gets a lot of help
from its friends. For a user's introduction to REVED, run the program and
ask for help -- it tries to be very helpful, but not too verbose.
;
DEFINE DEFAULT_SAVE_FILE=⊂"SAVED.REV"⊃;
DEFINE DEFAULT_CLOCK_RATE=25600;∂ Samples per second.;
DEFINE DEFAULT_GAIN=⊂0.75⊃;
DEFINE DEFAULT_DELAY=⊂0.05⊃; ∂ Seconds.;
DEFINE DEFAULT_NEAREST_PRIME_FLAG=TRUE;
DEFINE DEFAULT_PRIMES_OFFSET=1;
DEFINE DEFAULT_DURATION_FACTOR=⊂0.50⊃;
DEFINE DEFAULT_DELAY_FACTOR=⊂0.8⊃;
DEFINE DEFAULT_GAIN_FACTOR=⊂0.96⊃;
DEFINE MAIN_PIECE=0,
UNIT_LABEL_PIECE=1,
UNIT_PIECE=2,
TREE_UNIT_PIECE=3,
TREE_PIECE=4,
HELP_PIECE=5,
IMPULSE_PIECE=6,
CURSOR_PIECE=7;
DEFINE MAIN_LINES=7,
UNIT_LABEL_LINES=1,
UNIT_LINES=1,
TREE_UNIT_LINES=1,
TREE_LINES=13,
HELP_LINES=11;
DEFINE PER_LINE=24;
DEFINE HELP_POS=400;
DEFINE TOP_POS=96;
DEFINE UNIT_LABEL_POS=TOP_POS,
UNIT_POS=UNIT_LABEL_POS-((UNIT_LABEL_LINES)*PER_LINE),
TREE_UNIT_POS=UNIT_POS-((UNIT_LINES)*PER_LINE),
TREE_POS=TREE_UNIT_POS-((TREE_UNIT_LINES+1)*PER_LINE),
MAIN_POS=TREE_POS-((TREE_LINES+1)*PER_LINE);
DEFINE HELP_TEXT=⊂"
APPEND KILL ZERO_WORLD ""."" (Refresh display)
BRANCH LAST_IMPULSE #SAMPLES_DELAY
CLOCK_RATE NEAREST_PRIMES ← (No [CR]. Move to INPUT)
DELAY_TIME OUTPUT → (No [CR]. Move to OUTPUT)
EXIT PRECEDE ↔ (No [CR]. Move to BRANCH)
FREQUENCY REPLACE "" (Copy unit from node)
GAIN SAVE_THE_WORLD @ (Read commands from file)
HELP TIME_TO_DECAY ; (End of command file)
IMPULSE WALL_DISTANCE ? HELP prefix
"⊃;
∂ Declarations for unit reverberator manipulation routines.;
∂ These routines currently found in UNIT.SAI[REV,KS].;
EXTERNAL RECORD_CLASS REV_UNIT(
INTEGER NUMBER_OF_SAMPLES, CLOCK_RATE;
REAL GAIN, DELAY_TIME, DECAY_TIME);
EXTERNAL REAL PROCEDURE get_spec(
RECORD_POINTER(REV_UNIT) unit;
STRING which_spec);
EXTERNAL REAL PROCEDURE set_spec(
RECORD_POINTER(REV_UNIT) unit;
STRING new_spec, fix_spec;
REAL spec_val;
BOOLEAN use_prime(TRUE));
EXTERNAL RECORD_POINTER(REV_UNIT) PROCEDURE new_unit(
INTEGER rate(0);
REAL gain(0), delay(0);
BOOLEAN use_prime(TRUE));
EXTERNAL PROCEDURE free_unit(
REFERENCE RECORD_POINTER(REV_UNIT) unit);
EXTERNAL PROCEDURE copy_unit(
REFERENCE RECORD_POINTER(REV_UNIT) new_copy;
RECORD_POINTER(REV_UNIT) unit);
EXTERNAL INTEGER PROCEDURE nearest_prime(
REFERENCE INTEGER n);
EXTERNAL INTEGER ARRAY PRIMES[1:2]; ∂ Bounds are ignored.;
∂ Declarations for tree manipulation routines.;
∂ These routine currently found in TREE.SAI[REV,KS].;
EXTERNAL RECORD_CLASS REV_TREE(
RECORD_POINTER(REV_TREE) IN, OUT, ABURO;
RECORD_POINTER(REV_UNIT) UNIT);
EXTERNAL PROCEDURE insert_node(
REFERENCE RECORD_POINTER(REV_TREE) node;
RECORD_POINTER(REV_UNIT) unit;
STRING direction("OUTPUT");
BOOLEAN replace(FALSE));
EXTERNAL PROCEDURE first_node(
REFERENCE RECORD_POINTER(REV_TREE) node);
EXTERNAL PROCEDURE input_node(
REFERENCE RECORD_POINTER(REV_TREE) node);
EXTERNAL BOOLEAN PROCEDURE move_tree(
REFERENCE RECORD_POINTER(REV_TREE) node;
REFERENCE RECORD_POINTER(REV_UNIT) unit;
STRING direction("OUTPUT"));
EXTERNAL PROCEDURE free_node(
REFERENCE RECORD_POINTER(REV_TREE) node);
EXTERNAL PROCEDURE delete_node(
REFERENCE RECORD_POINTER(REV_TREE) node);
EXTERNAL BOOLEAN PROCEDURE traverse_tree(
REFERENCE RECORD_POINTER(REV_TREE) node;
REFERENCE RECORD_POINTER(REV_UNIT) unit;
REFERENCE INTEGER level;
REFERENCE BOOLEAN branching);
EXTERNAL BOOLEAN PROCEDURE is_root(
RECORD_POINTER(REV_TREE) node);
EXTERNAL RECORD_POINTER(REV_TREE) PROCEDURE new_tree;
EXTERNAL PROCEDURE free_tree(
REFERENCE RECORD_POINTER(REV_TREE) node);
∂ Declarations for impulse response display routine.;
∂ These routines currently found in IMPULS.SAI[REV,KS].;
EXTERNAL RECORD_CLASS REV_STATE_LIST(
RECORD_POINTER(REV_STATE_LIST) NEXT_UNIT;
REAL ARRAY DELAY_MEM; INTEGER MEM_SIZE, MEM_POSITION; REAL GAIN);
EXTERNAL RECORD_CLASS CASCADE(
INTEGER CLOCK_RATE;
RECORD_POINTER(REV_STATE_LIST) FIRST_UNIT);
EXTERNAL RECORD_POINTER(CASCADE) PROCEDURE new_cascade(
RECORD_POINTER(REV_TREE) node;
INTEGER path_length(INFINITY));
EXTERNAL PROCEDURE free_cascade(
REFERENCE RECORD_POINTER(CASCADE) chain);
EXTERNAL PROCEDURE IMPULS(
REFERENCE INTEGER id;
RECORD_POINTER(CASCADE) rev_chain;
REAL duration);
∂ Declarations for JAM's display routines.;
∂ These routines currently found in JAMLIB.REL[SUB,SYS].;
EXTERNAL PROCEDURE DSETUP(
INTEGER nwds;
REFERENCE INTEGER id);
DEFINE DGET(id,nwds)=⊂DSETUP(nwds,id)⊃;
EXTERNAL BOOLEAN PROCEDURE DRELS(
REFERENCE INTEGER id);
EXTERNAL BOOLEAN PROCEDURE DWRITE(
INTEGER id, chan);
EXTERNAL PROCEDURE WRITE(
INTEGER id, pog);
EXTERNAL PROCEDURE BUFCLR(
INTEGER id, nwds);
EXTERNAL PROCEDURE AVECT(
INTEGER id, X, Y);
EXTERNAL PROCEDURE AIVECT(
INTEGER id, X, Y);
EXTERNAL PROCEDURE RVECT(
INTEGER id, dX, dY);
EXTERNAL PROCEDURE RIVECT(
INTEGER id, dX, dY);
EXTERNAL PROCEDURE TYPLOC(
INTEGER ymin,ymax);
EXTERNAL PROCEDURE DTEXT(
INTEGER id;
STRING text;
REAL scale(0), angle(0));
∂ Declarations for piece of glass manipulation routines.;
∂ These routines currently found in PAPER.SAI, CURSOR.FAI, and DISPLA.FAI
respectively, all on [REV,KS].;
EXTERNAL PROCEDURE PPSIZE(
INTEGER #glitches, #lines(1));
EXTERNAL PROCEDURE PPSELECT(
INTEGER pp;
BOOLEAN keep_map(FALSE));
EXTERNAL PROCEDURE cursor(
INTEGER position, char("→"), pog(CURSOR_PIECE));
EXTERNAL PROCEDURE display(
INTEGER position;
STRING text;
INTEGER pog);
∂ Declarations for scanning routines.;
∂ These routines currently found in FETCH.SAI[REV,KS].;
EXTERNAL INTEGER DEVICEBREAKS,
TOKENBREAKS, DELIMITERBREAKS,
PERIODBREAKS, COMMABREAKS,
LINEBREAKS, CMMANDBREAKS; ∂ Funny name avoids LOADER conflict.;
EXTERNAL BOOLEAN PROCEDURE yes_fetch(
REFERENCE STRING arg;
REFERENCE BOOLEAN flag);
EXTERNAL BOOLEAN PROCEDURE file_fetch(
REFERENCE STRING arg;
REFERENCE STRING device, file);
EXTERNAL BOOLEAN PROCEDURE fix_fetch(
REFERENCE STRING arg;
REFERENCE STRING fix);
EXTERNAL BOOLEAN PROCEDURE real_fetch(
REFERENCE STRING arg;
REFERENCE REAL value, factor);
EXTERNAL BOOLEAN PROCEDURE #samp_fetch(
REFERENCE STRING arg;
REFERENCE INTEGER value, offset);
EXTERNAL PROCEDURE command_read(
REFERENCE STRING the_command, the_arguments;
REFERENCE BOOLEAN the_file_flag;
INTEGER the_in_channel;
REFERENCE INTEGER the_in_eof, the_in_break;
STRING immediate_chars("←→↔"));
∂ Sneaky TTY input routines.;
EXTERNAL INTEGER PROCEDURE SNEAKW;
EXTERNAL BOOLEAN PROCEDURE INSKIP(
INTEGER mode);
DEFINE INSKIPL=⊂INSKIP(1)⊃,
INSKIPC=⊂INSKIP(0)⊃;
EXTERNAL PROCEDURE instrument_print(
INTEGER channel;
RECORD_POINTER(REV_TREE) node);
∂ This routine currently found in INSTRU.SAI[REV,KS].;
INTEGER PROCEDURE file_channel(
STRING device, file;
STRING direction;
INTEGER mode;
REFERENCE INTEGER eof, break);
∂ Given a device and file name, plus desired mode and direction,
returns a channel doing the desired thing. Direction can be "in",
"out", or "both".
;
BEGIN "file channel"
INTEGER channel;
OWN INTEGER count;
BOOLEAN in, out, inflag, outflag;
IF
EQU(direction,"in")
THEN
out ← ¬(in ← TRUE)
ELSE IF
EQU(direction,"out")
THEN
in ← ¬(out ← TRUE)
ELSE IF
EQU(direction,"both")
THEN
in ← out ← TRUE
ELSE
RETURN(-1);
channel ← GETCHAN;
IF
channel < 0
THEN
RETURN(channel);
OPEN(channel,device,
mode LOR '770000,
(IF in THEN 2 ELSE 0),
(IF out THEN 2 ELSE 0),
count ← 80,
break,
eof ← -1);
IF
eof
THEN BEGIN
RELEASE(channel);
RETURN(-1);
END;
IF
in
THEN
LOOKUP(channel,file,inflag)
ELSE
inflag ← TRUE;
IF
out
THEN
ENTER(channel,file,outflag)
ELSE
outflag ← TRUE;
IF
inflag ∧ outflag
THEN BEGIN
RELEASE(channel);
RETURN(-1);
END;
RETURN(channel);
END "file channel";
PROCEDURE save_the_tree(
INTEGER channel;
RECORD_POINTER(REV_TREE) node);
∂ Saves the tree as a list of commands.
;
BEGIN "save the tree"
RECORD_POINTER(REV_TREE) tree;
RECORD_POINTER(REV_UNIT) unit;
INTEGER level,
i,
wid, dig;
BOOLEAN branching,
know_path;
STRING path;
GETFORMAT(wid,dig);
SETFORMAT(0,4);
tree ← node;
first_node(tree);
IF
¬move_tree(tree,unit,"OUTPUT")
THEN
RETURN;
CPRINT(channel,
↓,
"CLOCK_RATE ",CVS(get_spec(unit,"rate")),↓,
∂ Sets the clock rate;
"NEAREST_PRIMES NO",↓
∂ Prevents nearest primes so #samples are exact;
);
move_tree(tree,unit,"INPUT");
path ← NULL; know_path ← FALSE;
WHILE
traverse_tree(tree,unit,level ← 0,branching)
DO BEGIN
CPRINT(channel,
"#SAMPLES ",CVS(get_spec(unit,"#samples"))," GAIN",↓,
∂ Sets the #samples;
"GAIN ",CVF(get_spec(unit,"gain"))," DELAY",↓
∂ Sets the gain without changing #samples;
);
IF
level = 1
THEN
CPRINT(channel,
"APPEND",↓
∂ Inserts unit at OUTPUT;
)
ELSE IF
level = 0
THEN
CPRINT(channel,
"BRANCH",↓
∂ Inserts unit at BRANCH;
)
ELSE BEGIN
FOR
i ← level STEP 1
UNTIL
-1
DO
CPRINT(channel,
"←",↓
∂ Backs up thru INPUTs;
);
CPRINT(channel,
"BRANCH",↓
∂ Inserts unit at BRANCH;
);
END;
IF
¬know_path
THEN
IF
level = 1
THEN
path ← path&"→"
∂ Moves to node at OUTPUT;
ELSE IF
level = 0
THEN
path ← path&"↔"
∂ Moves to node at BRANCH;
ELSE
path ← path[1 TO ∞+level]&"↔";
∂ Forgets wrong path and moves to node at BRANCH;
IF
tree = node
THEN
know_path ← TRUE;
END;
CPRINT(channel,
↓
);
FOR
i ← level STEP 1
UNTIL
-1
DO
CPRINT(channel,
"←",↓
∂ Backs up thru INPUTs to root;
);
FOR
i ← 1
THRU
LENGTH(path)
DO
CPRINT(channel,
path[i FOR 1],↓
∂ Follows path thru tree to node;
);
SETFORMAT(wid,dig);
END "save the tree";
PROCEDURE save_the_world(
INTEGER channel;
RECORD_POINTER(REV_TREE) the_tree;
RECORD_POINTER(REV_UNIT) the_unit;
BOOLEAN the_nearest_prime_flag;
INTEGER the_primes_offset;
REAL the_duration_factor,
the_delay_factor,
the_gain_factor);
∂ Saves everything (but the impulse response) as commands in a file.
;
BEGIN "save the world"
INTEGER wid, dig;
GETFORMAT(wid,dig);
SETFORMAT(0,4);
CPRINT(channel,
"ZERO_WORLD",↓,
∂ Clears everything;
"IMPULSE *",CVF(the_duration_factor)[2 TO ∞],↓,
∂ Sets the duration factor;
"DELAY *",CVF(the_delay_factor)[2 TO ∞]," GAIN",↓,
∂ Sets the delay factor;
"GAIN *",CVF(the_gain_factor)[2 TO ∞]," DELAY",↓,
∂ Sets the gain factor;
"#SAMPLES ",(IF the_primes_offset ≥ 0 THEN "+" ELSE NULL),
the_primes_offset," GAIN",↓
∂ Sets the primes offset;
);
save_the_tree(channel,the_tree);
CPRINT(channel,
"CLOCK_RATE ",CVS(get_spec(the_unit,"rate")),↓,
∂ Sets the clock rate;
"#SAMPLES ",CVS(get_spec(the_unit,"#samples"))," GAIN",↓,
∂ Sets the #samples;
"GAIN ",CVF(get_spec(the_unit,"gain"))," DELAY",↓
∂ Sets the gain without changing #samples;
);
CPRINT(channel,
↓,
"NEAREST_PRIMES ",(IF the_nearest_prime_flag THEN "YES" ELSE "NO"),↓,
∂ Sets the nearest prime flag;
";",↓
∂ Terminates the file input;
);
SETFORMAT(wid,dig);
END "save the world";
PROCEDURE HELP_clear;
∂ Clears the piece of glass that the list of commands is displayed on.
;
START_CODE "HELP CLEAR"
DEFINE PGACT='715040000000;
HRRI 1,'400000;
LSH 1,-HELP_PIECE;
ANDCAI 1,-1;
PGACT 0(1);
END "HELP CLEAR";
PROCEDURE DCLEAR(
INTEGER pog);
∂ Clears the display using JAM's routines. Used to clear impulse display.
;
BEGIN "DCLEAR"
INTEGER id;
DGET(id,3);
WRITE(id,pog);
END "DCLEAR";
PROCEDURE esc_break(
INTEGER char;
BOOLEAN break(FALSE));
∂ Executes the terminal ESC or BREAK function specified. If break is TRUE, then
will do [BREAK]char, else [ESC]char.
;
START_CODE
MOVSI 2,'4000; ∂ ESC/BREAK function;
HRR 2,char;
SKIPE break;
TRO 2,'400; ∂ Set this bit for BREAK function;
HRROI 1,2; ∂ Indicates list of commands 1 long - just [ESC]/[BREAK] char;
CALLI 1,'400121; ∂ TTYSET UUO;
END;
PROCEDURE label_print(
INTEGER position, pog;
REAL delay_factor, gain_factor, duration_factor;
INTEGER primes_offset;
BOOLEAN nearest_prime_flag);
BEGIN "label print"
INTEGER wid, dig;
STRING text;
∂ Produce a line that looks like this:
" Delay(*.80) Gain(*.96) Time[I*.6] #Samples(+5)Y Wall Frequency Clock";
SETFORMAT(4,2);
text ← " Delay(*"&CVF(delay_factor)[2 TO ∞]&")";
text ← text&" Gain(*"&CVF(gain_factor)[2 TO ∞]&")";
SETFORMAT(3,1);
text ← text&" Time[I*"&CVF(duration_factor)[2 TO ∞]&"]";
SETFORMAT(0,0);
text ← text&" #Samples(+"&CVS(primes_offset)&")"&
(IF nearest_prime_flag THEN "Y" ELSE "N");
text ← text&" Wall Frequency Clock";
display(position,text,pog);
END "label print";
PROCEDURE unit_print(
INTEGER position, pog;
RECORD_POINTER(REV_UNIT) unit);
BEGIN "unit print"
INTEGER wid, dig;
STRING text, number;
DEFINE PadTo(n)=⊂
" "[1 TO (n-LENGTH(text)-LENGTH(number))]⊃;
IF
unit = NULL_RECORD
THEN BEGIN
display(position,"[Input Signal]",pog);
RETURN;
END;
GETFORMAT(wid,dig);
text ← NULL;
SETFORMAT(0,2);
number ← CVF(get_spec(unit,"delay")*1000.0);
text ← text&(PadTo(7)&number&"ms");
SETFORMAT(0,3);
number ← CVF(get_spec(unit,"gain"));
text ← text&(PadTo(19)&number);
SETFORMAT(0,2);
number ← CVF(get_spec(unit,"decay"));
text ← text&(PadTo(30)&number&"sec");
SETFORMAT(0,0);
number ← CVS(get_spec(unit,"#samples"));
text ← text&(PadTo(45)&number);
SETFORMAT(0,2);
number ← CVF(get_spec(unit,"wall"));
text ← text&(PadTo(59)&number&"m");
SETFORMAT(0,2);
number ← CVF(get_spec(unit,"frequency"));
text ← text&(PadTo(71)&number&"Hz");
SETFORMAT(0,0);
number ← CVS(get_spec(unit,"rate"));
text ← text&(PadTo(80)&number&"/sec");
display(position,text,pog);
SETFORMAT(wid,dig);
END "unit print";
PROCEDURE units_print(
RECORD_POINTER(REV_UNIT) scratch, current;
REAL delay_factor, gain_factor, duration_factor;
INTEGER primes_offset;
BOOLEAN nearest_prime_flag;
REFERENCE BOOLEAN refresh_flag, factors_update_flag,
scratch_update_flag;
BOOLEAN current_update_flag);
BEGIN "units print"
IF
refresh_flag
∨
factors_update_flag
THEN BEGIN
label_print(UNIT_LABEL_POS,UNIT_LABEL_PIECE,
delay_factor,gain_factor,duration_factor,
primes_offset,nearest_prime_flag
);
factors_update_flag ← FALSE;
END;
IF
refresh_flag
∨
scratch_update_flag
THEN BEGIN
unit_print(UNIT_POS,UNIT_PIECE,scratch);
scratch_update_flag ← FALSE;
END;
IF
refresh_flag
∨
current_update_flag
THEN BEGIN
unit_print(TREE_UNIT_POS,TREE_UNIT_PIECE,current);
END;
END "units print";
PROCEDURE tree_print(
RECORD_POINTER(REV_TREE) node);
BEGIN "tree print"
RECORD_POINTER(REV_TREE) tree;
RECORD_POINTER(REV_UNIT) unit;
INTEGER level, indent,
wid, dig;
BOOLEAN branching;
STRING text;
text ← NULL;
GETFORMAT(wid,dig);
SETFORMAT(0,2);
IF
node = NULL_RECORD
THEN BEGIN
display(TREE_POS,"NULL TREE"&↓,TREE_PIECE);
RETURN;
END;
text ← text&("[Input Signal,");
tree ← node;
first_node(tree);
IF
move_tree(tree,unit,"OUTPUT")
THEN BEGIN
text ← text&(" Clock rate = "&CVS(get_spec(unit,"rate")));
move_tree(tree,unit,"INPUT");
END
ELSE
text ← text&(" Clock rate is undefined.");
text ← text&("]");
level ← 0; branching ← FALSE;
WHILE
traverse_tree(tree,unit,level,branching)
DO BEGIN
IF
¬branching
THEN
level ← 0;
text ← text&(↓);
FOR
indent ← 1
THRU
level
DO
text ← text&(" ");
text ← text&("[Delay:"&CVF(get_spec(unit,"delay")*1000.0)[2 TO ∞]&"ms");
SETFORMAT(0,3);
text ← text&(", Gain:"&CVF(get_spec(unit,"gain"))
[(IF get_spec(unit,"gain") < 0 THEN 1 ELSE 2) TO ∞]);
SETFORMAT(0,2);
text ← text&(", Time:"&CVF(get_spec(unit,"decay"))[2 TO ∞]&"secs]");
END;
text ← text&(↓&" ");
display(TREE_POS,text,TREE_PIECE);
SETFORMAT(wid,dig);
END "tree print";
PROCEDURE update_display(
RECORD_POINTER(REV_TREE) the_tree;
RECORD_POINTER(REV_UNIT) the_unit;
REAL the_delay_factor, the_gain_factor, the_duration_factor;
INTEGER the_primes_offset;
BOOLEAN the_nearest_prime_flag;
REFERENCE INTEGER the_previous_position;
REFERENCE BOOLEAN the_unit_update_flag,
the_tree_update_flag,
the_move_update_flag,
the_factors_update_flag,
the_refresh_flag);
BEGIN "update display"
RECORD_POINTER(REV_UNIT) the_tree_unit;
RECORD_POINTER(REV_TREE) tree;
RECORD_POINTER(REV_UNIT) unit;
INTEGER line, level, indent;
BOOLEAN branching;
SAFE OWN INTEGER ARRAY PPINFO[0:24];
∂ Do a PPINFO uuo and check whether the display was manually cleared.;
CODE('702240000000,PPINFO[0]);
the_refresh_flag ← the_refresh_flag ∨
(PPINFO[2] LAND '200000000000);
IF
the_refresh_flag
THEN BEGIN
PPSELECT(1); ∂ So interactions previous to REVED not clobbered.;
TYPLOC(MAIN_POS-(PER_LINE*MAIN_LINES),MAIN_POS);
PPSIZE(MAIN_LINES); ∂ This call is not superfluous! Sets lines/glitch = 1;
esc_break("P",FALSE); ∂ Refresh page;
END;
the_move_update_flag ← the_move_update_flag ∨ the_tree_update_flag;
move_tree(the_tree,the_tree_unit,"SELF");
units_print(
the_unit, the_tree_unit,
the_delay_factor, the_gain_factor, the_duration_factor,
the_primes_offset,
the_nearest_prime_flag,
the_refresh_flag, the_factors_update_flag,
the_unit_update_flag, the_move_update_flag);
IF
the_tree_update_flag
∨
the_refresh_flag
THEN BEGIN
tree_print(the_tree);
the_tree_update_flag ← FALSE;
END;
∂ ... update_display ... continued.;
IF
the_move_update_flag
∨
the_refresh_flag
THEN BEGIN
tree ← the_tree;
first_node(tree);
line ← TREE_POS-(PER_LINE*the_previous_position);
cursor(line," ",CURSOR_PIECE);
the_previous_position ← 0;
WHILE
tree ≠ the_tree
∧
traverse_tree(tree,unit,level,branching)
DO
the_previous_position ←
the_previous_position+1;
line ← TREE_POS-(PER_LINE*the_previous_position);
cursor(line,"→",CURSOR_PIECE);
the_move_update_flag ← FALSE;
END;
the_refresh_flag ← FALSE;
END "update display";
∂ Declarations for THE_WORLD.;
STRING the_in_device, the_in_file;
INTEGER the_in_channel, the_in_eof, the_in_break;
BOOLEAN the_file_flag;
STRING the_command, the_arguments;
RECORD_POINTER(REV_TREE) the_tree;
RECORD_POINTER(REV_UNIT) the_unit, the_tree_unit;
∂ the_tree_unit is non-essential;
BOOLEAN the_nearest_prime_flag;
INTEGER the_primes_offset;
REAL the_duration_factor,
the_delay_factor,
the_gain_factor;
INTEGER the_id,
the_previous_position;
BOOLEAN the_unit_update_flag,
the_tree_update_flag,
the_move_update_flag,
the_factors_update_flag,
the_refresh_flag;
BOOLEAN the_describe_flag, the_describing_flag;
PROCEDURE initialize_the_world;
BEGIN "initialize the world"
∂ BEWARE BEWARE BEWARE ... Uses all GLOBAL variables.;
DCLEAR(IMPULSE_PIECE);
the_command ← the_arguments ← NULL;
the_describe_flag ← the_describing_flag ← FALSE;
free_tree(the_tree);
free_node(the_tree);
the_tree ← new_tree;
free_unit(the_tree_unit);
free_unit(the_unit);
the_unit ← new_unit(DEFAULT_CLOCK_RATE,DEFAULT_GAIN,DEFAULT_DELAY);
the_nearest_prime_flag ← DEFAULT_NEAREST_PRIME_FLAG;
the_primes_offset ← DEFAULT_PRIMES_OFFSET;
the_duration_factor ← DEFAULT_DURATION_FACTOR;
the_delay_factor ← DEFAULT_DELAY_FACTOR;
the_gain_factor ← DEFAULT_GAIN_FACTOR;
the_unit_update_flag ← TRUE;
the_tree_update_flag ← TRUE;
the_move_update_flag ← TRUE;
the_factors_update_flag ← TRUE;
the_refresh_flag ← TRUE;
display(HELP_POS,HELP_TEXT,HELP_PIECE);
END "initialize the world";
∂ Top level.;
EXTERNAL INTEGER RPGSW;
the_in_device ← the_in_file ← NULL;
the_in_channel ← the_in_eof ← the_in_break ← 0;
the_file_flag ← FALSE;
IF
RPGSW
THEN BEGIN
the_in_device ← "DSK";
the_in_file ← DEFAULT_SAVE_FILE;
the_in_channel ←
file_channel(the_in_device,the_in_file,"in",'00,
the_in_eof,the_in_break);
IF
the_in_channel ≥ 0
THEN
the_file_flag ← TRUE;
END;
the_id ← 0;
∂ display(HELP_POS,HELP_TEXT,HELP_PIECE);
PPSELECT(1); ∂ So interactions previous to REVED not clobbered.;
TYPLOC(MAIN_POS-(PER_LINE*MAIN_LINES),MAIN_POS);
PPSIZE(MAIN_LINES); ∂ This call is not superfluous! Sets lines/glitch = 1;
the_previous_position ← 0;
initialize_the_world;
WHILE
TRUE
DO BEGIN "command loop"
LABEL Unknown_command;
the_describe_flag ←
the_describing_flag ←
the_describe_flag ∧ ¬the_describing_flag;
IF
¬the_describing_flag
THEN BEGIN
TTYUP(TRUE);
IF
¬the_file_flag
THEN BEGIN
update_display(
the_tree,
the_unit,
the_delay_factor,
the_gain_factor,
the_duration_factor,
the_primes_offset,
the_nearest_prime_flag,
the_previous_position,
the_unit_update_flag,
the_tree_update_flag,
the_move_update_flag,
the_factors_update_flag,
the_refresh_flag);
PRINT("?: ");
END;
command_read(the_command,the_arguments,
the_file_flag,
the_in_channel,
the_in_eof, the_in_break);
END;
CASE
the_command LAND '177
OF BEGIN "command select"
DEFINE DESCRIPTION(text)=⊂
IF
the_describe_flag
THEN BEGIN
PRINT(↓,
text,
↓
);
the_describe_flag ← FALSE;
END
ELSE ⊃;
DEFINE PREFIX_EQU(s1,s2)=
⊂EQU(s1,s2[1 FOR LENGTH(s1)])⊃;
∂ If s2="FOO" is TRUE for s1=NULL,"F","FO","FOO", but not
"X","FX","FOX","FOOX",etc. ;
DEFINE CHECK_COMMAND(a_command)=⊂
IF
¬ PREFIX_EQU(the_command,a_command)
THEN
GO TO Unknown_command ∂ Lord have mercy! A GO TO!!;
ELSE ⊃;
["A"] ∂ APPEND;
CHECK_COMMAND("APPEND")
DESCRIPTION(
<"APPEND
Inserts a copy of the scratch unit into the tree following the current
unit and preceding all of the outputs of the current unit. The inserted
unit will be the new current unit.">)
BEGIN
insert_node(the_tree,the_unit,"OUTPUT");
the_tree_update_flag ← TRUE;
END;
["B"] ∂ BRANCH;
CHECK_COMMAND("BRANCH")
DESCRIPTION(
<"BRANCH
Inserts a copy of the scratch unit into the tree in parallel with the
current unit, so that the inserted unit shares the same input source
with the current unit. The inserted unit will be the new current unit.">)
BEGIN
insert_node(the_tree,the_unit,"BRANCH");
the_tree_update_flag ← TRUE;
END;
["C"] ∂ CLOCK_RATE;
CHECK_COMMAND("CLOCK_RATE")
DESCRIPTION(
<"CLOCK_RATE {value{K}} {fix}
Sets the clock rate for the scratch unit to the given value. If the
letter ""K"" follows the value, then it is multiplied by 1000.0. If
the value is less than 1000.0 (as in 256), then it is multiplied by 100.0.
The fix option is the same as in the DELAY command.">)
BEGIN
REAL value, realtmp;
STRING fix;
real_fetch(the_arguments,
value ← get_spec(the_unit,"rate"),
realtmp ← 0);
IF
value < 1000.0
THEN
value ← value*100;
fix_fetch(the_arguments,fix ← "decay");
set_spec(the_unit,"rate",fix,value,the_nearest_prime_flag);
the_unit_update_flag ← TRUE;
END;
["D"] ∂ DELAY_TIME;
CHECK_COMMAND("DELAY_TIME")
DESCRIPTION(
<"DELAY_TIME {value | [*|/]{factor}} {fix}
Sets the delay time in milliseconds for the scratch unit to either the
specified value or else the specified factor times (or divided into) the
present value. If ""*"" or ""/"" is typed without a factor, the last one given
is used. Fix (default GAIN) is the name of the parameter to be held constant.">)
BEGIN
REAL value;
STRING fix;
real_fetch(the_arguments,
value ← get_spec(the_unit,"delay")*1000.0,
the_delay_factor);
IF
the_delay_factor = 0.0
THEN
the_delay_factor ← DEFAULT_DELAY_FACTOR;
IF
value = 0.0
THEN
value ← DEFAULT_DELAY*1000.0;
fix_fetch(the_arguments,fix ← "gain");
set_spec(the_unit,"delay",fix,value*0.001,the_nearest_prime_flag);
the_unit_update_flag ← TRUE;
the_factors_update_flag ← TRUE;
END;
["E"] ∂ EXIT;
CHECK_COMMAND("EXIT")
DESCRIPTION(
<"EXIT {file}
Returns to the monitor after saving the state of the editor in the
specified file. If no name is given the state is not saved. Unspecified
fields of the specified file are filled in from the name DSK:",DEFAULT_SAVE_FILE,".
The ""@"" command will read in saved states.">)
BEGIN
∂ Use same default file as @, SAVE_THE_WORLD;
STRING device, file;
INTEGER channel, eof, break;
IF
file_fetch(the_arguments,device ← "DSK",file ← DEFAULT_SAVE_FILE)
THEN BEGIN
channel ← file_channel(device,file,"out",'00,eof,break);
IF
channel ≥ 0
THEN BEGIN
save_the_world(channel,
the_tree,
the_unit,
the_nearest_prime_flag,
the_primes_offset,
the_duration_factor,
the_delay_factor,
the_gain_factor);
RELEASE(channel);
DONE "command loop";
END
ELSE
PRINT(↓,"Can't write file ",device,":",file,↓);
END
ELSE
DONE "command loop";
END;
["F"] ∂ FREQUENCY;
CHECK_COMMAND("FREQUENCY")
DESCRIPTION(
<"FREQUENCY {value} {fix}
Sets the delay time of the scratch unit to the reciprocal of the
specified value. Fix is the same as for the DELAY_TIME command.">)
BEGIN
REAL value, realtmp;
STRING fix;
real_fetch(the_arguments,
value ← get_spec(the_unit,"frequency"),
realtmp ← 0);
fix_fetch(the_arguments,fix ← "gain");
set_spec(the_unit,"frequency",fix,value,the_nearest_prime_flag);
the_unit_update_flag ← TRUE;
END;
["G"] ∂ GAIN;
CHECK_COMMAND("GAIN")
DESCRIPTION(
<"GAIN {value | [*|/]{factor}} {fix}
Sets the gain of the scratch unit to either the specified value or the
given factor times (or divided into) the present value. If ""*"" or ""/""
is typed without a factor, the last one given is used. Fix is the name
of the parameter to be held constant. The default is DELAY.">)
BEGIN
REAL value;
STRING fix;
real_fetch(the_arguments,
value ← get_spec(the_unit,"gain"),
the_gain_factor);
IF
the_gain_factor = 0.0
THEN
the_gain_factor ← DEFAULT_GAIN_FACTOR;
IF
value = 0.0
THEN
value ← DEFAULT_GAIN;
fix_fetch(the_arguments,fix ← "delay");
set_spec(the_unit,"gain",fix,value,the_nearest_prime_flag);
the_unit_update_flag ← TRUE;
the_factors_update_flag ← TRUE;
END;
["H"] ∂ HELP;
CHECK_COMMAND("HELP")
DESCRIPTION(
<"HELP
Displays a list of all available command names. For information
about specific commands, type ""?"" followed by the name of the
command. For general information, read REVED.KS[DOC,MUS].">)
BEGIN
DCLEAR(IMPULSE_PIECE);
display(HELP_POS,HELP_TEXT,HELP_PIECE);
the_refresh_flag ← TRUE;
END;
["I"] ∂ IMPULSE;
CHECK_COMMAND("IMPULSE")
DESCRIPTION(
<"IMPULSE {duration | [*|/]{factor}} {file}
Displays the impulse response of the path from the Input Signal thru the
current unit for the specified duration, or if none is given, then for
the longest decay time on that path. A factor applies to the default time,
otherwise behaving as in DELAY_TIME. A file name saves the display.">)
BEGIN
∂ May also allow path_length in future.;
REAL duration;
STRING device, file;
BOOLEAN save;
INTEGER channel, eof, break;
RECORD_POINTER(CASCADE) chain;
RECORD_POINTER(REV_TREE) tmp_tree;
RECORD_POINTER(REV_UNIT) tmp_unit;
tmp_tree ← the_tree;
IF
move_tree(tmp_tree,tmp_unit,"SELF")
∧
¬is_root(tmp_tree)
THEN
duration ← get_spec(tmp_unit,"decay")
ELSE
duration ← 1.0;
WHILE
move_tree(tmp_tree,tmp_unit,"INPUT")
∧
¬is_root(tmp_tree)
DO
duration ← duration MAX get_spec(tmp_unit,"decay");
real_fetch(the_arguments,
duration,
the_duration_factor);
IF
the_duration_factor = 0.0
THEN
the_duration_factor ← DEFAULT_DURATION_FACTOR;
save ← file_fetch(the_arguments,
device ← "DSK",
file ← "IMPLSE.PLT");
chain ← new_cascade(the_tree);
IMPULS(the_id,chain,duration);
IF
¬(chain = NULL_RECORD
∧
the_file_flag)
THEN BEGIN
HELP_clear;
WRITE(the_id,IMPULSE_PIECE);
END;
IF
save
THEN BEGIN
channel ← file_channel(device,file,"out",'17,eof,break);
IF
channel ≥ 0
THEN BEGIN
DWRITE(the_id,channel);
RELEASE(channel);
END
ELSE
PRINT(↓,"Can't write file ",device,":",file,↓);
END;
free_cascade(chain);
the_factors_update_flag ← TRUE;
the_refresh_flag ← TRUE;
END;
["K"] ∂ KILL;
CHECK_COMMAND("KILL")
DESCRIPTION(
<"KILL {YES}
Removes the current unit from the tree and throws it away. If you don't
say YES in the command, it will ask if you really mean it (since the unit
cannot be recovered). Any output units of the current unit will then get
input from the input to the current unit. A new current unit is chosen.">)
BEGIN
STRING reply;
BOOLEAN do_it;
IF
¬yes_fetch(the_arguments,do_it ← FALSE)
THEN BEGIN
PRINT("REALLY KILL? ");
TTYUP(TRUE);
reply ← INCHWL;
yes_fetch(reply,do_it ← FALSE);
END;
IF
do_it
THEN
delete_node(the_tree);
the_tree_update_flag ← TRUE;
END;
["L"] ∂ LAST_IMPULSE;
CHECK_COMMAND("LAST_IMPULSE")
DESCRIPTION(
<"LAST_IMPULSE {file}
The last impulse response displayed with the IMPULSE command may be
redisplayed and optionally saved in a file. The default file will only
be used to fill in unspecified fields of a named file; it is IMPLSE.PLT.
To list on the XGP, try ""R XIP;X1.4;Y1.4;H2;⊗file;"".">)
BEGIN
STRING device, file;
INTEGER channel, eof, break;
BOOLEAN save;
IF
the_id ≠ 0
THEN BEGIN
save ← file_fetch(the_arguments,
device ← "DSK",
file ← "IMPLSE.PLT");
HELP_clear;
WRITE(the_id,IMPULSE_PIECE);
IF
save
THEN BEGIN
channel ← file_channel(device,file,"out",'17,eof,break);
IF
channel ≥ 0
THEN BEGIN
DWRITE(the_id,channel);
RELEASE(channel);
END
ELSE
PRINT(↓,"Can't write file ",device,":",file,↓);
END;
END;
the_refresh_flag ← TRUE;
END;
["N"] ∂ NEAREST_PRIMES;
CHECK_COMMAND("NEAREST_PRIMES")
DESCRIPTION(
<"NEAREST_PRIMES {YES | NO}
Sets the flag which determines whether the number of samples of delay
for the scratch unit will be coerced to be prime numbers (a good idea).
If no argument is given, the flag is set to the opposite of its current
state. The initial value of this flag is YES.">)
BEGIN
yes_fetch(the_arguments,
the_nearest_prime_flag ← ¬the_nearest_prime_flag);
the_factors_update_flag ← TRUE;
END;
["O"] ∂ OUTPUT;
CHECK_COMMAND("OUTPUT")
DESCRIPTION(
<"OUTPUT {file}
Writes out the tree as an instrument suitable for compilation by the
music compiler. The default file name is ALLPAS.MUS.">)
BEGIN
STRING device, file;
INTEGER channel, eof, break;
file_fetch(the_arguments,device ← "DSK",file ← "ALLPAS.MUS");
channel ← file_channel(device,file,"out",'00,eof,break);
IF
channel ≥ 0
THEN BEGIN
instrument_print(channel,the_tree);
RELEASE(channel);
END
ELSE
PRINT(↓,"Can't write file ",device,":",file,↓);
END;
["P"] ∂ PRECEDE;
CHECK_COMMAND("PRECEDE")
DESCRIPTION(
<"PRECEDE
Inserts a copy of the scratch unit into the tree preceding the current
unit, so that the current unit will then get its input from the new
unit. The inserted unit becomes the current unit.">)
BEGIN
insert_node(the_tree,the_unit,"INPUT");
the_tree_update_flag ← TRUE;
END;
["R"] ∂ REPLACE;
CHECK_COMMAND("REPLACE")
DESCRIPTION(
<"REPLACE
The parameters of the current unit are replaced by the parameters of the
scratch unit. To copy parameters the from the current unit to the
scratch unit, see the "" (read as ditto) command.">)
BEGIN
insert_node(the_tree,the_unit,"SELF",TRUE);
the_tree_update_flag ← TRUE;
END;
["S"] ∂ SAVE_THE_WORLD;
CHECK_COMMAND("SAVE_THE_WORLD")
DESCRIPTION(
<"SAVE_THE_WORLD {file}
The entire state of the editor is saved as a sequence of commands in the
specified file. The default file used is ",DEFAULT_SAVE_FILE,". The ""@""
command, which uses the same default file, will read in a saved file.">)
BEGIN
∂ Use same default file as @ ;
STRING device, file;
INTEGER channel, eof, break;
file_fetch(the_arguments,device ← "DSK",file ← DEFAULT_SAVE_FILE);
channel ← file_channel(device,file,"out",'00,eof,break);
IF
channel ≥ 0
THEN BEGIN
save_the_world(channel,
the_tree,
the_unit,
the_nearest_prime_flag,
the_primes_offset,
the_duration_factor,
the_delay_factor,
the_gain_factor);
RELEASE(channel);
END
ELSE
PRINT(↓,"Can't write file ",device,":",file,↓);
END;
["T"] ∂ TIME_TO_DECAY;
CHECK_COMMAND("TIME_TO_DECAY")
DESCRIPTION(
<"TIME_TO_DECAY {value} {fix}
Sets the time to decay parameter for the scratch unit. This is the time
required for an input signal to decay 60dB. Fix is the name of the
parameter to be held constant. The default is DELAY.">)
BEGIN
REAL value, realtmp;
STRING fix;
real_fetch(the_arguments,
value ← get_spec(the_unit,"decay"),
realtmp ← 0);
fix_fetch(the_arguments,fix ← "delay");
set_spec(the_unit,"decay",fix,value,the_nearest_prime_flag);
the_unit_update_flag ← TRUE;
END;
["W"] ∂ WALL_DISTANCE;
CHECK_COMMAND("WALL_DISTANCE")
DESCRIPTION(
<"WALL_DISTANCE {value} {fix}
Sets the delay time for the scratch unit so that it corresponds to the
given distance (in meters) from a reflective surface. Fix is the same
as for the DELAY_TIME command.">)
BEGIN
REAL value, realtmp;
STRING fix;
real_fetch(the_arguments,
value ← get_spec(the_unit,"wall"),
realtmp ← 0);
fix_fetch(the_arguments,fix ← "gain");
set_spec(the_unit,"wall",fix,value,the_nearest_prime_flag);
the_unit_update_flag ← TRUE;
END;
["Z"] ∂ ZERO_WORLD;
CHECK_COMMAND("ZERO_WORLD")
DESCRIPTION(
<"ZERO_WORLD
Re-initializes the state of the editor, throwing away anything done so
far. This is a useful command with which to begin command files.">)
BEGIN
initialize_the_world;
END;
["#"] ∂ #SAMPLES;
CHECK_COMMAND("#SAMPLES")
DESCRIPTION(
<"#SAMPLES {value | [+|-]{offset}} {fix}
Sets the number of samples of delay for the scratch unit to the given
value. If an offset is given instead, it is taken as the number of
prime numbers to offset from the current value. Fix is the name of the
parameter to hold constant. The default is DECAY.">)
BEGIN
INTEGER value;
STRING fix;
#samp_fetch(the_arguments,
value ← get_spec(the_unit,"#samples"),
the_primes_offset);
fix_fetch(the_arguments,fix ← "decay");
set_spec(the_unit,"#samples",fix,value,the_nearest_prime_flag);
the_unit_update_flag ← TRUE;
the_factors_update_flag ← TRUE;
END;
[""""] ∂ COPY_NODE_INTO_UNIT;
CHECK_COMMAND("""")
DESCRIPTION(
<"""
Copy the parameters of the current unit into the scratch unit. This is
the inverse of the REPLACE command, and is how you edit units already in
the tree.">)
BEGIN
move_tree(the_tree,the_unit,"SELF");
the_unit_update_flag ← TRUE;
END;
["."] ∂ REFRESH_DISPLAY;
CHECK_COMMAND(".")
DESCRIPTION(
<".
Refreshes the display if it has been cleared by an ESC or BREAK keyboard
command or otherwise garbaged.">)
BEGIN
the_refresh_flag ← TRUE;
END;
["@"] ∂ READ_COMMANDS_FROM_FILE;
DESCRIPTION(
<"@ {file}
Take all further commands from the specified file until either an
end-of-file or a "";"" command. This command will restore the state
of the editor from the files created by the SAVE_THE_WORLD and EXIT
commands. The default file is ",DEFAULT_SAVE_FILE,".">)
BEGIN
∂ Use same default file as SAVE_WORLD.;
IF
the_file_flag
THEN
PRINT(↓,"No @ nesting.",↓)
ELSE BEGIN
file_fetch(the_arguments,
the_in_device ← "DSK",the_in_file ← DEFAULT_SAVE_FILE);
the_in_channel ←
file_channel(the_in_device,the_in_file,"in",'00,
the_in_eof,the_in_break);
IF
the_in_channel < 0
THEN
PRINT(↓,"Can't read file ",the_in_device,":",the_in_file,↓)
ELSE
the_file_flag ← TRUE;
END;
END;
[";"] ∂ READ_COMMANDS_FROM_TTY;
DESCRIPTION(
<";
When read from a file of commands, this is equivalent to an end-of-file;
otherwise it has no effect.">)
BEGIN
IF
the_file_flag
THEN BEGIN
RELEASE(the_in_channel);
PRINT(↓);
END;
the_file_flag ← FALSE;
END;
["?"] ∂ HELP prefix;
DESCRIPTION(
<"? {command}
Types out a brief description of the command named. The format of the
first line will be: ""{}"" surround options, ""[]"" surround required
arguments, ""|"" separates alternatives, ""lower_case"" indicates a class
of possible arguments (using a suggestive name).">)
BEGIN
∂ Describe command;
INTEGER break;
the_command ← SCAN(the_arguments,CMMANDBREAKS,break);
IF
LENGTH(the_command) = 0
THEN
IF
LENGTH(the_arguments) > 0
THEN
the_command ← LOP(the_arguments);
IF
LENGTH(the_command) = 0
THEN
PRINT(↓,
"An introduction to this program may be found in REVED.KS[DOC,MUS]. For
information about specific commands type ""?"" followed by the name of
the command. The command HELP displays a list of all the commands. All
commands may be abbreviated by their first letter, and only enough
blanks to insure decipherability need be typed.",
↓
)
ELSE
the_describe_flag ← TRUE;
END;
["←"] ∂ MOVE_TO_INPUT;
DESCRIPTION(
<"← (no carriage return required)
Makes the input unit of the current unit the new current unit. Normally
requires no carriage return; however, if another command was typed first
and then backspaced over, a carriage return may be needed.">)
BEGIN
the_move_update_flag ←
move_tree(the_tree,the_tree_unit,"INPUT")
∨
the_move_update_flag;
END;
["→"] ∂ MOVE_TO_OUTPUT;
DESCRIPTION(
<"← (no carriage return required)
Makes the first listed output unit of the current unit the new current
unit. Normally requires no carriage return; however, if another command
was typed first and then backspaced over, a carriage return may be needed.">)
BEGIN
the_move_update_flag ←
move_tree(the_tree,the_tree_unit,"OUTPUT")
∨
the_move_update_flag;
END;
["↔"] ∂ MOVE_TO_BRANCH;
DESCRIPTION(
<"↔ (no carriage return required)
Makes the next branch unit receiving input from the same unit as the
current unit the new current unit. Normally requires no carriage return;
however, if another command was typed first and then backspaced over, a
carriage return may be needed.">)
BEGIN
the_move_update_flag ←
move_tree(the_tree,the_tree_unit,"BRANCH")
∨
the_move_update_flag;
END;
[0] ∂ NULL COMMAND;
;
ELSE ∂ UNRECOGNIZED COMMAND;
Unknown_command:
DESCRIPTION(
<"Unknown command. Type ? for help.">)
BEGIN
PRINT(" Unknown command. Type ? for help.",↓);
END
END "command select";
END "command loop";
PPSELECT(0);
esc_break("N",TRUE); ∂ Clear and normalize page;
END "FACADE"